package com.gitee.l0km.javadocreader;

import java.util.LinkedHashSet;
import java.util.Set;

import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.sun.source.doctree.*;
import com.sun.source.util.SimpleDocTreeVisitor;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;;


/**
 * 读取所有注释标签({@link BlockTagTree})，如：'@author','@param',保存到{@link #blockTags}
 */
class BlockTagExtracter extends SimpleDocTreeVisitor<Void,Void> {
	
//	private final SetMultimap<String, BlockTagTree> blockTags = MultimapBuilder.linkedHashKeys().hashSetValues().build();
	private final SetMultimap<String, BlockTagTree> blockTags = Multimaps.newSetMultimap(Maps.newLinkedHashMap(),
			LinkedHashSet::new);

    BlockTagExtracter() {
    }

    BlockTagExtracter extract(DocCommentTree docTree) {
    	if(null != docTree) {
    		docTree.accept(this,null);
    	}
    	return this;
    }
    
	public Set<String> allTags() {
		return blockTags.keySet();
	}

	/**
	 * 返回指定标签对应的{@link BlockTagTree}集合，没有找到返回{@code null}
	 * @param tagname 标签名,如 '@param'
	 */
	Set<BlockTagTree> tags(String tagname) {
    	return blockTags.get(tagname);
    }

	/**
	 * 返回指定标签对应的{@link BlockTagTree}， 没有找到返回{@code null}，匹配的结果有超过一个则抛出异常
	 * 
	 * @param tagname 标签名,如 '@return'
	 */
	BlockTagTree tag(String tagname) {
		Set<BlockTagTree> tags = tags(tagname);
		if (tags != null && !tags.isEmpty()) {
			checkState(tags.size() == 1, "UNEXPECTED MULTI %s", tagname);
			return tags.iterator().next();
		}
		return null;
	}

	/**
	 * 返回指定名称的参数标签('@param')对应的{@link ParamTree}没有找到返回{@code null}
	 * @param name 参数名
	 */
	ParamTree paramTag(String name) {
		if (null != name) {
			if (name.startsWith("<") && name.endsWith(">")) {
				name = name.substring(1, name.length() - 1);
			}
			for (BlockTagTree tag : blockTags.get("@param")) {
				checkArgument(tag instanceof ParamTree, "MISMATCH TYPE,%s required",
						ParamTree.class.getSimpleName());
				ParamTree paramTag = (ParamTree) tag;
				if (name.equals(paramTag.getName().toString())) {
					return paramTag;
				}
			}
		}
		return null;
	}

    @Override
	protected Void defaultAction(DocTree node, Void p) {
    	if(node instanceof BlockTagTree) {
    		blockTags.put("@"+ node.getKind().tagName, (BlockTagTree) node);
    	}
		return super.defaultAction(node, p);
	}

	@Override 
    public Void visitDocComment(DocCommentTree node, Void p) {
		return super.visit(node.getBlockTags(),null);
    }
}